package com.ys.servers.points.verticle;

import com.ys.servers.common.data.ReturnData;
import com.ys.servers.common.data.UserType;
import com.ys.servers.common.mq.InternalEventData;
import com.ys.servers.common.util.CommonUtils;
import com.ys.servers.common.verticle.BasicRestfulVerticle;
import com.ys.servers.points.data.PointsType;
import com.ys.servers.points.service.PointsTypeService;
import com.ys.servers.points.service.UserPointsService;
import com.ys.servers.points.service.UserSignInfoService;
import com.ys.servers.points.service.impl.PointsServiceImpl;
import com.ys.servers.points.service.impl.UserPointsServiceImpl;
import com.ys.servers.points.service.impl.UserSignInfoServiceImpl;
import io.vertx.core.Future;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.handler.BodyHandler;

import java.util.Map;
import java.util.HashMap;

/**
 * Created by taotao on 2017/5/5.
 */
public class PointsVerticle extends BasicRestfulVerticle {

    private PointsTypeService pointsService;

    private UserPointsService userPointsService;

    private UserSignInfoService userSignInfoService;

    public PointsTypeService getPointsService() {
        return pointsService;
    }

    public UserPointsService getUserPointsService() {
        return userPointsService;
    }

    public PointsVerticle setUserPointsService(UserPointsService userPointsService) {
        this.userPointsService = userPointsService;
        return this;
    }

    public PointsVerticle setPointsService(PointsTypeService pointsService) {
        this.pointsService = pointsService;
        return this;
    }

    public UserSignInfoService getUserSignInfoService() {
        return userSignInfoService;
    }

    public PointsVerticle setUserSignInfoService(UserSignInfoService userSignInfoService) {
        this.userSignInfoService = userSignInfoService;
        return this;
    }

    public static final String SERVICE_NAME = "points-service";

    private static final String POINTS_TYPE_ADD = "/";
    private static final String POINTS_TYPE_RETRIEVE = "/:id";
    private static final String POINTS_TYPE_RETRIEVE_ALL = "/";
    private static final String POINTS_TYPE_UPDATE = "/";
    private static final String POINTS_TYPE_DELETE = "/:id";
    private static final String POINTS_TYPE_RESTORE = "/restore/:id";
    private static final String POINTS_TYPE_DISABLE = "/disable";
    private static final String POINTS_TYPE_ENABLE = "/enable";
    private static final String POINTS_TYPE_DESC = "/desc";


    private static final String USER_POINTS_ADD = "/user";
    //private static final String USER_POINTS_INFO = "/user";
    private static final String USER_POINTS_INFO = "/user/:userId/:userType/:days/:limit/:offset";

    //temp
    private static final String USER_SIGNIN = "/sign";
    private static final String GET_USER_SIGNIN = "/sign/:userId/:userType";


    @Override
    public void start(Future<Void> future) throws Exception {

        super.start();
        setPointsService(new PointsServiceImpl())
                .setUserPointsService(new UserPointsServiceImpl())
                .setUserSignInfoService(new UserSignInfoServiceImpl());

        final Router router = Router.router(vertx);
        // body handler
        router.route().handler(BodyHandler.create());
        // api route handler
        router.post(POINTS_TYPE_ADD).handler(this::addPointsType);
        router.get(POINTS_TYPE_RETRIEVE).handler(this::getPointsType);
        router.get(POINTS_TYPE_RETRIEVE_ALL).handler(this::getAllPointsType);
        router.put(POINTS_TYPE_UPDATE).handler(this::updatePointsType);
        router.get(POINTS_TYPE_RESTORE).handler(this::restorePointsType);
        router.get(POINTS_TYPE_DESC).handler(this::getAllPointsTypeDesc);
        router.delete(POINTS_TYPE_DELETE).handler(this::deletePointsType);

        router.get(USER_POINTS_INFO).handler(this::getUserRecentlyPoints);
        router.post(USER_POINTS_ADD).handler(this::addUserPoints);

        router.post(POINTS_TYPE_DISABLE).handler(this::disablePointsType);

        router.post(POINTS_TYPE_ENABLE).handler(this::enablePointsType);


        router.post(USER_SIGNIN).handler(this::userSign);
        router.get(GET_USER_SIGNIN).handler(this::getUserSignInfo);

        String host = config().getString("points.rest.http.address", "0.0.0.0");
        int port = config().getInteger("points.rest.http.port", 18887);

        // create HTTP server and publish REST service
        createHttpServer(router, host, port)
                .compose(serverCreated -> publishHttpEndpoint(SERVICE_NAME, host, port))
                .setHandler(future.completer());
    }

    private void getAllPointsTypeDesc(RoutingContext context) {
        getPointsService().getAllPointsTypeDesc(restfulReturnDataHandler(context));
    }

    private void disablePointsType(RoutingContext context) {
        JsonObject paras = context.getBodyAsJson();
        String pointsId = paras.getValue("pointsId").toString();
        getPointsService().disablePointsType(pointsId, restfulReturnDataHandler(context));
    }

    private void enablePointsType(RoutingContext context) {
        JsonObject paras = context.getBodyAsJson();
        String pointsId = paras.getValue("pointsId").toString();
        getPointsService().enablePointsType(pointsId, restfulReturnDataHandler(context));
    }

    private void restorePointsType(RoutingContext context) {
        String id = context.request().getParam("id");
        getPointsService().restorePointsType(id, restfulReturnDataHandler(context));
    }

    private void updatePointsType(RoutingContext context) {

        getPointsService().updatePointsType(genPointsTypeFromContext(context), restfulReturnDataHandler(context));
    }

    private void getAllPointsType(RoutingContext context) {
        getPointsService().getAllPointsType(restfulReturnDataHandler(context));
    }

    private void getPointsType(RoutingContext context) {
        String id = context.request().getParam("id");
        getPointsService().getPointsType(id, restfulReturnDataHandler(context));
    }

    private void deletePointsType(RoutingContext context) {
        String id = context.request().getParam("id");
        getPointsService().removePointsType(id, restfulReturnDataHandler(context));
    }

    private void addPointsType(RoutingContext context) {
        getPointsService().addPointsType(genPointsTypeFromContext(context), restfulReturnDataHandler(context));

    }

    private void getUserRecentlyPoints(RoutingContext context) {
        String id = context.request().getParam("userId");
        String userType = context.request().getParam("userType");
        String days = context.request().getParam("days");
        String limit = context.request().getParam("limit");
        String offset = context.request().getParam("offset");
        getUserPointsService().getRecentUserPointsLog(Integer.parseInt(days),
                limit == null ? 20 : Integer.parseInt(limit),
                offset == null ? 0 : Integer.parseInt(offset),
                Long.parseLong(id), UserType.values()[Integer.parseInt(userType)],
                restfulReturnDataHandler(context));
    }

    private void addUserPoints(RoutingContext context) {
        //"/user/:userId/:userType/:pointsId";
        JsonObject paras = context.getBodyAsJson();
        String userId = paras.getValue("userId").toString();
        String userType = paras.getValue("userType").toString();
        String pointsType = paras.getValue("pointsId").toString();
        getUserPointsService().addUserPoints(Long.parseLong(userId), UserType.values()[Integer.parseInt(userType)]
                , pointsType, restfulReturnDataHandler(context));


    }

    private PointsType genPointsTypeFromContext(RoutingContext context) {

        JsonObject paras = context.getBodyAsJson();
        PointsType pointsType = PointsType.parseJsonObject(paras, PointsType.class);

       /* JsonObject paras = context.getBodyAsJson();
        long id = Long.parseLong(paras.getValue("_id").toString());
        String desc = paras.getString("desc");
        String title = paras.getString("title");
        //short type = Short.parseShort(paras.getString("type"));
        short type = Short.parseShort(paras.getValue("type").toString());
        short loopType = Short.parseShort(paras.getValue("loopType").toString());
        short loopUnit = Short.parseShort(paras.getValue("loopUnit").toString());
        short maxTime = Short.parseShort(paras.getValue("maxTime").toString());
        int order = Integer.parseInt(paras.getValue("order").toString());
        PointsType pointsType = new PointsType().setLoopType(PointsLoopType.values()[loopType])
                .setLoopUnit(LoopTypeUnit.values()[loopUnit]).setMaxTime(maxTime).setDesc(desc).setTitle(title).setOrder(order);
        pointsType.setId(Long.toString(id));*/
        return pointsType;
    }


    private void testInternalAddUserPoints(InternalEventData internalEventData, Future<InternalEventData> respFuture) {
        System.out.println("test ok");
        String a = internalEventData.getApiName();
        String b = internalEventData.getRecordAddress();
        //     Future<InternalEventData> respFuture2 = Future.future();
        InternalEventData result = new InternalEventData().setApiName("re").setRecordAddress("22");
        respFuture.complete(result);
    }

    private void clearUserPoints(InternalEventData internalEventData, Future<InternalEventData> respFuture) {
        String userId = internalEventData.getParas().getString("userId");
        UserType userType = UserType.values()[internalEventData.getParas().getInteger("userType")];
        String pointsId = internalEventData.getParas().getString("pointsTypeId");
        this.getUserPointsService().clearUserPoints(userId, userType, pointsId, res -> {
            if (CommonUtils.validAsyncResult(res)) {
                internalEventData.setParas(res.result());
                respFuture.complete(internalEventData);
            } else {
                respFuture.fail(res.cause());
            }
        });
        //internalEventData.setParas()

    }

    @Override
    protected String interName() {
        return "inter-" + SERVICE_NAME;
    }

    @Override
    protected void initInternalDispatcher() {
        internalHandlerMap.put("add-points", this::testInternalAddUserPoints);
        internalHandlerMap.put("clear-points", this::clearUserPoints);
    }


    private void userSign(RoutingContext context) {
        JsonObject paras = context.getBodyAsJson();
        String userId = paras.getValue("userId").toString();
        String userType = paras.getValue("userType").toString();

        getUserSignInfoService().userSign(userId, UserType.values()[Integer.parseInt(userType)], userSignInfoAsyncResult -> {
            Future<ReturnData> future = Future.future();
            future.setHandler(restfulReturnDataHandler(context));
            ReturnData returnData = new ReturnData();
            Map<String, Object> data = new HashMap();
            returnData.setData(data);
            if (CommonUtils.validAsyncResult(userSignInfoAsyncResult)) {
                //签到成功
                data.put("suc", true);
                data.put("signInfo", userSignInfoAsyncResult.result());
                getUserPointsService().addUserPoints(Long.parseLong(userId), UserType.values()[Integer.parseInt(userType)], "3", addPointsRes -> {
                    if (CommonUtils.validAsyncResult(addPointsRes)) {
                        //增加积分成功
                        data.put("pointsInfo", addPointsRes.result());
                    } else {
                        //增加积分失败
                        data.put("pointsInfo", "");
                    }
                    future.complete(returnData);
                });
            } else {
                //签到失败
                data.put("suc", false);
                data.put("signInfo", "");
                returnData.setError(true);
                returnData.setErrorMsg("SignIn Fail");
                future.complete(returnData);
            }
        });

       /* InternalEventData internalEventData = new InternalEventData().setApiName("add-points").setRecordAddress("points-service")
                .setParas(new JsonObject().put("userId", 1342543));
        interService(internalEventData).setHandler(res -> {
            System.out.println(res.result());
        });*/
    }

    private void getUserSignInfo(RoutingContext context) {
        String userId = context.request().getParam("userId");
        String userType = context.request().getParam("userType");
        getUserSignInfoService().getUserSignInfo(userId, UserType.values()[Integer.parseInt(userType)], restfulReturnDataHandler(context));
    }
}
